/*
 * socket_interface.c
 *
 *  Created on: 04/01/2013
 *      Author: Julian Ovalle
 */

#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <netdb.h>

#include "message_def.h"
#include "socket_interface.h"


int openSocket(struct sockaddr_in* myName) {

    int s;
    struct servent *serv;
    serv = getservbyname(SOCKET_SERVICE_NAME, "tcp");

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
#ifdef SOCK_INTERFACE_DEBUG
        perror("openSocket.Error abriendo socket");
#endif
        return -1;
    }

    myName->sin_family = AF_INET;
    myName->sin_port = serv->s_port;
    myName->sin_addr.s_addr = INADDR_ANY;

    printf("\nPuerto %d\n", htons(serv->s_port));

    int yes = 1;
    if ( setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1 )
    {
        perror("openSocket:setsockopt");
    }

    if (bind(s, (struct sockaddr*) myName, sizeof(*(myName))) < 0) {
#ifdef SOCK_INTERFACE_DEBUG
        perror("openSocket.error haciendo el bind");
#endif
        return -1;
    }

    if (listen(s, SOMAXCONN) < 0) {
#ifdef SOCK_INTERFACE_DEBUG
        perror("openSocket.error al escuchar conexiones");
#endif
        return -1;
    }

    return s;
}


int socketSend(int sfd, const void* data, size_t size, struct sockaddr* addr,
        socklen_t addrlen, int timeout_s, int timeout_ms) {

    struct timeval timeout;
    int r = -2;
    fd_set set;
    timeout.tv_sec = timeout_s;
    timeout.tv_usec = timeout_ms * 1000;
    FD_ZERO(&set);
    FD_SET(sfd, &set);

    if (select(FD_SETSIZE, NULL, &set, NULL, &timeout) > 0) {
        r = sendto(sfd, (char*) data, size, 0, (const struct sockaddr *) addr,
                (socklen_t) addrlen);
        if (r == -1) {
#ifdef SOCK_INTERFACE_DEBUG
            perror("socketSend.sendto");
#endif
            return -2;
        } else {
            return r;
        }
    } else {
#ifdef SOCK_INTERFACE_DEBUG
        fprintf(stderr, "socketSend.sendto.timeout\n");
#endif
        return -1;
    }
}

int socketReceive(int sfd, const void* buf, size_t size, struct sockaddr* addr,
        socklen_t addrlen, int timeout_s, int timeout_ms) {
    int r = -2;
    struct timeval timeout;
    fd_set set;

    timeout.tv_sec = timeout_s;
    timeout.tv_usec = timeout_ms * 1000;
    FD_ZERO(&set);
    FD_SET(sfd, &set);

    if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) {
        r = recvfrom(sfd, (char *) buf, size, 0, (const struct sockaddr *) addr,
                (socklen_t) addrlen);
        if (r < 0) {
#ifdef SOCK_INTERFACE_DEBUG
            fprintf(stderr, "\nsocketReceive.error in socket ");
#endif
            return (-2);
        } else {
            return r;
        }
    } else {
#ifdef SOCK_INTERFACE_DEBUG
        fprintf(stderr, "socketReceive.rcvfrom.timeout\n");
#endif
        return (-1);
    }
}
